﻿using System; // For String, Int32, Console, ArgumentException

using System.Text; // For Encoding

// For IOException

using System.Net.Sockets; // For TcpClient, NetworkStream, SocketException
using  Kortex.Network_mapper;
using System.Threading;
using System.Windows.Forms;
using System.Collections.Generic;
using Kortex.Communication_objs;
using Kortex.Container;
using System.Net.NetworkInformation;

namespace Kortex.TCPClient
{
    public class tcpCLient
    {
        public tcpCLient(NetworkMapper obj)
        { 
        
        upperIf = obj;
        BuffLen = 1024;
        byteBuffer = new byte[BuffLen];
        }
       
        int servPort = 8889;
        String server = "10.128.64.167"; // Server name or IP address
        // Convert input String to bytes
        TcpClient client = null;
        NetworkStream netStream = null;
        byte[] byteBuffer = null;
        NetworkMapper upperIf;
        Thread t = null;
        Thread Workert = null;
        Int32 BuffLen = 1024;

        bool run = true;
        List<General_responce> responceChain = new List<General_responce>();

        public void responceWorker_optimize()
        {
            
            Monitor.Enter(responceChain);
                if (responceChain.Count > 0)
                {
                    upperIf.send(responceChain[0]);
                    
                    if (responceChain.Count > 0) //isn't Strange i have to put this check as in Power off and reboot case i am closing and clear this chain 
                        responceChain.RemoveAt(0);
                    
                }
                try
                {
                    Monitor.Exit(responceChain);
                }
            catch(Exception er)
               {
               }
        }

        private void responceWorker()
        {
            while (run)
            {
                
                if (responceChain.Count > 0)
                {
                    upperIf.send(responceChain[0]);
                    Monitor.Enter(responceChain);
                    if (responceChain.Count > 0) //isn't Strange i have to put this check as in Power off and reboot case i am closing and clear this chain 
                    responceChain.RemoveAt(0);
                    Monitor.Exit(responceChain);
                }
                else
                {
                    Thread.Sleep(100);
                }
               
            }
        }

        
        
        /*
        public void readThread()
        {
            int bytesRcvd = 0; // Bytes received in last read
            General_responce[] resp = null;

            while (run)
            {
                try
                {
                    bytesRcvd = netStream.Read(byteBuffer, 0, BuffLen);

                   
                    

                    upperIf.send(Encoding.ASCII.GetString(byteBuffer, 0, bytesRcvd));
                   

                   

                    //upperIf.send(Encoding.ASCII.GetString(byteBuffer, 0, bytesRcvd));
                }
                catch (System.IO.IOException exp)
                {
                    Console.Write("IOexception" + exp.Message);
                }


            }

        }
         * */

        bool SocketConnected(Socket s)
        {
            bool part1 = s.Poll(1000, SelectMode.SelectRead);
            bool part2 = (s.Available == 0);
            if (part1 & part2)
            {//connection is closed
                return false;
            }
            return true;
        }
       

       
        public void readThread()
        {
            int bytesRcvd = 0; // Bytes received in last read
            General_responce []resp = null;
            string RecevJson = string.Empty;
            int count = 0;

            while (run)
            {
                try
                {
                    bytesRcvd = netStream.Read(byteBuffer, 0, BuffLen);

                    if (bytesRcvd <= 0)
                        count++;
                    else
                    {
                        RecevJson = Encoding.ASCII.GetString(byteBuffer, 0, bytesRcvd);
                        ReqRespDebugInfo DebugObj = new ReqRespDebugInfo(RecevJson, reqResType.type_res);
                        resp = upperIf.GetResponceObject(RecevJson);
                        upperIf.updateDebugInfo(DebugObj);

                        Monitor.Enter(responceChain);
                        if (resp != null)
                            foreach (General_responce rsp in resp)
                                responceChain.Add(rsp);
                        Monitor.Exit(responceChain);
                    }

                    /*if (count > 10)
                    {
                        run = false;
                        client.Close();
                        netStream.Close();
                        netStream = null;
                        client = null;
                    }
                     * */
                    

                    //upperIf.send(Encoding.ASCII.GetString(byteBuffer, 0, bytesRcvd));
                }
                catch (System.IO.IOException exp)
                {
                  // MessageBox.Show("IOexception" + exp.Message);
                    run = false;
                    if (client != null)
                        client.Close();
                    if (netStream != null)
                        netStream.Close();
                    netStream = null;
                    client = null;
                }
                catch(Exception er)
                {
                  //  MessageBox.Show(er.Message);
                    run = false;
                    if (client != null)
                    client.Close();
                    if(netStream != null)
                    netStream.Close();
                    netStream = null;
                    client = null;
                
                }
                
                
            }
        
        }
         

        #region String to Byte Array
        public static byte C2b(char c)
        {
            if ((int)c < 256) return (byte)c;
            throw new Exception("character overflows a byte");
        }
        public static byte[] S2b(string value)
        {
            byte[] buffer = new byte[value.Length];
            for (int i = 0; i < buffer.Length; i++)
            {
                buffer[i] = C2b(value[i]);
            }

            return buffer;
        }
        #endregion

        public void Send(string json)
        {
            byte[] byteBuff = S2b(json);
            if (netStream != null)
            {
                ReqRespDebugInfo DebugObj = new ReqRespDebugInfo(json, reqResType.type_req);
                netStream.Write(byteBuff, 0, json.Length);
                upperIf.updateDebugInfo(DebugObj);

            }
            else
            {
                MessageBox.Show("MecuryTool is not Connected please Connect First");
            
            }

            
        }

        public void Close()
        {
            run = false;


            try
            {
                if (client != null)
                {
                    client.Close();
                    client = null;
                }
            }
            catch (Exception er)
            { }


            try
            {
                if (netStream != null)
                {
                    netStream.Dispose();
                    netStream.Close();
                    netStream = null;
                }
            }
            catch(Exception er)
            { 
            
            }
           
            try
            {
                if (t != null && Thread.CurrentThread.ManagedThreadId != t.ManagedThreadId)
                {
                    t.Abort();
                    t = null;
                }
            }
            catch (Exception er)
            { 
            }


            try
            {
                if (Workert != null && Thread.CurrentThread.ManagedThreadId != Workert.ManagedThreadId)
                {
                    
                    Workert.Abort();
                    Workert = null;


                }
            }
            catch (Exception er)
            { 
            
            }

            try
            {
                if (responceChain != null)
                    responceChain.Clear();
            }
            catch (Exception er)
            {
 
            }

            try
            {
                Monitor.Exit(responceChain);
            }
            catch(Exception er)
            { 
            }
            //Thread.Sleep(600);

            
            
        }


        public void Start(string n_server_ip, int n_port,bool Optimize)
        {
            server = n_server_ip;
            servPort = n_port;
            run = true;
            try
            {
                // Create socket that is connected to server on specified port
                client = new TcpClient(n_server_ip, n_port);
                netStream = client.GetStream();
                responceChain.Clear();
                t = new Thread(readThread);
                t.Name = "KP TcpRead_" + n_server_ip + "_" + n_port.ToString();
                t.Start();

                if (!Optimize)
                {
                     Workert = new Thread(responceWorker);
                     Workert.Name = "KP tcp Worker" + n_server_ip + "_" + n_port.ToString();
                     Workert.SetApartmentState(ApartmentState.STA); 
                     Workert.Start();
                }

            }
            catch (Exception e)
            {

                //MessageBox.Show(e.Message);

                if (netStream != null)
                    netStream.Close();

                if (client != null)
                    client.Close();
                throw new Exception(e.Message);
                //Console.WriteLine(e.Message);

            }
            //   finally
            {

                //   netStream.Close();

                //   client.Close();

            }

        }
    

    public void Start( string n_server_ip, int n_port)
    {
        server = n_server_ip;
        servPort = n_port;
        run = true;
        try
        {
            // Create socket that is connected to server on specified port
            client = new TcpClient(n_server_ip, n_port);
            netStream = client.GetStream();
            responceChain.Clear();
            t = new Thread(readThread);
            t.Name = "KP TcpRead_" + n_server_ip + "_" + n_port.ToString();
            t.Start();
            Workert = new Thread(responceWorker);
            Workert.Name = "KP tcp Worker" + n_server_ip + "_" + n_port.ToString();

            Workert.Start();

            
        }
        catch (Exception e)
        {

            //MessageBox.Show(e.Message);

            if (netStream!=null)   
            netStream.Close();

            if (client != null)      
            client.Close();
            throw new Exception(e.Message);
            //Console.WriteLine(e.Message);

        }
     //   finally
        {

         //   netStream.Close();

         //   client.Close();

        }

    }
    


    }

}


